package com.we.wfc.common.base;

import com.google.common.collect.Lists;
import com.we.wfc.common.enums.ReturnCode;
import com.we.wfc.common.pojo.ResultPoJo;
import com.we.wfc.common.utils.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.OK;

/**
 * @Description: 封装全局异常机制
 * @Author:Liangzy(Feeling)
 * @Date:Create in 2019/11/6 6:15 下午
 */
@Slf4j
@RestControllerAdvice
public class BaseExceptionHandler {

    private final String SECURITY_EXCEPTION_MESSAGE =
            "org.springframework.security.access.AccessDeniedException: 不允许访问";

    /**
     * 捕捉自定义的异常
     *
     * @param exception
     * @return ResponseEntity<ResultPoJo>
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = {BaseException.class})
    public ResponseEntity<ResultPoJo> handleServiceException(BaseException exception) {
        log.error("【XXX异常】:错误码->" + exception.getErrorCode() + "错误信息->" + exception.getErrorMessage());
        return new ResponseEntity(new ResultPoJo(
                CommonUtil.emptyStr(exception.getErrorCode()).orElse(ReturnCode.SERVER_EXCEPTION.getCode()),
                CommonUtil.emptyStr(exception.getErrorMessage()).orElse(ReturnCode.SERVER_EXCEPTION.getMsg())),
                OK);
    }

    /**
     * 自定义参数异常拦截
     */
    @ExceptionHandler(value = { MethodArgumentNotValidException.class, BindException.class })
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResultPoJo validException(HttpServletRequest request, Exception ex) {
        List<ObjectError> errors = Lists.newArrayList();
        if (ex instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException c = (MethodArgumentNotValidException) ex;
            errors =c.getBindingResult().getAllErrors();
        }
        if (ex instanceof BindException) {
            BindException c = (BindException) ex;
            errors =c.getBindingResult().getAllErrors();
        }
        StringJoiner stringJoiner = new StringJoiner(" , ", "{ ", " }");
        errors.forEach(error -> {
            List<String> rs = Stream.of(error.toString().split(";"))
                    .filter(mg -> mg.contains("default message"))
                    .map(mg -> Stream.of(mg.split(",")).filter(s -> s.contains("default message")).findFirst().orElse(""))
                    .collect(Collectors.toList());
            List<String> list = CommonUtil.splitStr4Temp(String.join("",rs), "default message [{}]");
            stringJoiner.add("[" + list.get(0) + "]" + list.get(1));
        });
        return ResultPoJo.ok().setCode(HttpStatus.BAD_REQUEST.value() + "").setMsg("参数异常："+ stringJoiner.toString());
    }

    /**
     * 捕获其他异常
     *
     * @param exception exception
     * @return ResponseEntity
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
    public ResponseEntity<ResultPoJo> hadleServerException(Exception exception) {
        //定义返回异常
        ResultPoJo<ReturnCode> poJo = new ResultPoJo<>();
        //打印堆栈信息
        exception.printStackTrace();
        HttpStatus httpStatus = INTERNAL_SERVER_ERROR;

        if (exception instanceof BaseException) {
            poJo.setCode(((BaseException) exception).getErrorCode());
            poJo.setMsg(((BaseException) exception).getErrorMessage());
            log.warn("server exception code is {} message is {}" + poJo.getCode(), poJo.getMsg());
            //设置HTTP状态
            httpStatus = OK;
        } else if (exception instanceof HttpMessageNotReadableException) {
            poJo.setCode(ReturnCode.PARAMETER_TYPE_IS_INCORRECT.getCode());
            poJo.setMsg(ReturnCode.PARAMETER_TYPE_IS_INCORRECT.getMsg());
            log.warn("Parameter type is incorrect exception code is {} message is {}" +
                    poJo.getCode(), poJo.getMsg());
            //设置HTTP状态
            httpStatus = OK;
        } else if (exception instanceof MissingServletRequestParameterException) {
            poJo.setCode(ReturnCode.MISSING_PARAMETERS.getCode());
            poJo.setMsg(ReturnCode.MISSING_PARAMETERS.getMsg());
            log.warn("Missing parameters exception code is {} message is {}" +
                    poJo.getCode(), poJo.getMsg());
            //设置HTTP状态
            httpStatus = OK;
        } else if (exception instanceof HttpRequestMethodNotSupportedException) {
            poJo.setCode(ReturnCode.HTTP_METHOD_NOT_SUPPORT.getCode());
            poJo.setMsg(ReturnCode.HTTP_METHOD_NOT_SUPPORT.getMsg());
            log.warn("http method not support exception code is {} message is {}" +
                    poJo.getCode(), poJo.getMsg());
            //设置HTTP状态
            httpStatus = OK;
        } else if (this.SECURITY_EXCEPTION_MESSAGE.equals(exception.toString())) {
            poJo.setCode(ReturnCode.INSUFFICIENT_PERMISSIONS.getCode());
            poJo.setMsg(ReturnCode.INSUFFICIENT_PERMISSIONS.getMsg());
            log.warn("Insufficient permissions exception code is {} message is {}" +
                    poJo.getCode(), poJo.getMsg());
            //设置HTTP状态
            httpStatus = OK;
        } else {
            poJo.setCode(ReturnCode.SERVER_EXCEPTION.getCode());
            poJo.setMsg(ReturnCode.SERVER_EXCEPTION.getMsg());
            log.warn("server exception exception code is {} message is {}" +
                    poJo.getCode(), poJo.getMsg());
            //设置HTTP状态
            httpStatus = OK;
        }

        return new ResponseEntity(poJo, httpStatus);
    }
}
